<!DOCTYPE HTML>
<html lang="en">
<head>
<title>Loop (read file contents) - Syntax &amp; Usage | AutoHotkey</title>
<meta name="description" content="The Loop Read statement retrieves the lines in a text file, one at a time." />
<meta name="ahk:equiv-v2" content="commands/LoopRead.htm" />
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<link href="../static/theme.css" rel="stylesheet" type="text/css" />
<script src="../static/content.js" type="text/javascript"></script>
</head>
<body>

<h1>Loop (read file contents)</h1>

<p>Retrieves the lines in a text file, one at a time (performs better than <a href="FileReadLine.htm">FileReadLine</a>).</p>

<pre class="Syntax"><span class="func">Loop, Read</span>, InputFile <span class="optional">, OutputFile</span></pre>
<h2>Parameters</h2>
<dl>

  <dt>Read</dt>
  <dd><p>This parameter must be the word READ.</p></dd>

  <dt>InputFile</dt>
  <dd><p>The name of the text file whose contents will be read by the loop, which is assumed to be in <a href="../Variables.htm#WorkingDir">%A_WorkingDir%</a> if an absolute path isn't specified. Windows and Unix formats are supported; that is, the file's lines may end in either carriage return and linefeed (`r`n) or just linefeed (`n).</p></dd>

  <dt>OutputFile</dt>
  <dd><p>(Optional) The name of the file to be kept open for the duration of the loop, which is assumed to be in <a href="../Variables.htm#WorkingDir">%A_WorkingDir%</a> if an absolute path isn't specified.</p>
      <p>Within the loop's body, use the <a href="FileAppend.htm">FileAppend</a> command with only one parameter (the text to be written) to append to this special file. Appending to a file in this manner performs better than using <a href="FileAppend.htm">FileAppend</a> in its 2-parameter mode because the file does not need to be closed and re-opened for each operation. Remember to include a linefeed (`n) after the text, if desired.</p>
      <p>The file is not opened if nothing is ever written to it. This happens if the Loop performs zero iterations or if it never uses the <a href="FileAppend.htm">FileAppend</a> command.</p>
          <p><strong>End of line (EOL) translation</strong>: To disable EOL translation, prepend an asterisk to the filename. This causes each linefeed character (`n) to be written as a single linefeed (LF) rather than the Windows standard of CR+LF. For example: <code><strong>*</strong>C:\My Unix File.txt</code>. Even without the asterisk, EOL translation is disabled automatically if the Loop's <u>first</u> use of <a href="FileAppend.htm">FileAppend</a> writes any carriage return and linefeed pairs (`r`n).</p>
      <p><strong>Standard Output (stdout)</strong>: Specifying an asterisk (*) for <em>OutputFile</em> sends any text written by <a href="FileAppend.htm">FileAppend</a> to standard output (stdout). Although such output can be redirected to a file, piped to another EXE, or captured by <a href="_ErrorStdOut.htm">fancy text editors</a>, it will not appear at the command prompt it was launched from. See <a href="FileAppend.htm">FileAppend</a> for more details.</p>
      <p><strong>Escaped Commas</strong>: Unlike the last parameter of most other commands, commas in <em>OutputFile</em> must be escaped (`,).</p></dd>

</dl>

<h2>Remarks</h2>
<p>A file-reading loop is useful when you want to operate on each line contained in a text file, one at a time. It performs better than using <a href="FileReadLine.htm">FileReadLine</a> because: 1) the file can be kept open for the entire operation; and 2) the file does not have to be re-scanned each time to find the requested line number.</p>
<p id="LoopReadLine">The built-in variable <strong>A_LoopReadLine</strong> exists within any file-reading loop. It contains the contents of the current line excluding the carriage return and linefeed (`r`n) that marks the end of the line. If an inner file-reading loop is enclosed by an outer file-reading loop, the innermost loop's file-line will take precedence.</p>
<p>Lines up to 65,534 characters long can be read. If the length of a line exceeds this, its remaining characters will be read during the next loop iteration.</p>
<p><a href="StringSplit.htm">StringSplit</a> or a <a href="LoopParse.htm">parsing loop</a> is often used inside a file-reading loop to parse the contents of each line retrieved from <em>InputFile</em>. For example, if <em>InputFile</em>'s lines are each a series of tab-delimited fields, those fields can individually retrieved as in this example:</p>
<pre>Loop, read, C:\Database Export.txt
{
    Loop, parse, A_LoopReadLine, %A_Tab%
    {
        MsgBox, Field number %A_Index% is %A_LoopField%.
    }
}</pre>
<p>To load an entire file into a variable, use <a href="FileRead.htm">FileRead</a> because it performs much better than a loop (especially for large files).</p>
<p>To have multiple files open simultaneously, use <a href="FileOpen.htm">FileOpen()</a>.</p>
<p>See <a href="Loop.htm">Loop</a> for information about <a href="Block.htm">Blocks</a>, <a href="Break.htm">Break</a>, <a href="Continue.htm">Continue</a>, and the A_Index variable (which exists in every type of loop).</p>
<p>To control how the file is decoded when no byte order mark is present, use <a href="FileEncoding.htm">FileEncoding</a>.</p>

<h2>Related</h2>
<p><a href="FileEncoding.htm">FileEncoding</a>, <a href="FileOpen.htm">FileOpen()</a> / <a href="../objects/File.htm">File Object</a>, <a href="FileRead.htm">FileRead</a>, <a href="FileReadLine.htm">FileReadLine</a>, <a href="FileAppend.htm">FileAppend</a>, <a href="Sort.htm">Sort</a>, <a href="Loop.htm">Loop</a>, <a href="Break.htm">Break</a>, <a href="Continue.htm">Continue</a>, <a href="Block.htm">Blocks</a>, <a href="FileSetAttrib.htm">FileSetAttrib</a>, <a href="FileSetTime.htm">FileSetTime</a></p>

<h2>Examples</h2>
<div class="ex" id="ExFileAppend">
<p><a href="#ExFileAppend">#1</a>: Only those lines of the 1st file that contain the word FAMILY will be written to the 2nd file. Uncomment the first line to overwrite rather than append to any existing file.</p>
<pre><em>;FileDelete, C:\Docs\Family Addresses.txt</em>

Loop, read, C:\Docs\Address List.txt, C:\Docs\Family Addresses.txt
{
    if InStr(A_LoopReadLine, "family")
        FileAppend, %A_LoopReadLine%`n
}</pre>
</div>

<div class="ex" id="ExLastLine">
<p><a href="#ExLastLine">#2</a>: Retrieve the last line from a text file.</p>
<pre>Loop, read, C:\Log File.txt
    last_line := A_LoopReadLine  <em>; When loop finishes, this will hold the last line.</em></pre>
</div>

<div class="ex" id="ExURL">
<p><a href="#ExURL">#3</a>: A working script that attempts to extract all FTP and HTTP URLs from a text or HTML file:</p>
<pre>FileSelectFile, SourceFile, 3,, Pick a text or HTML file to analyze.
if (SourceFile = "")
    return  <em>; This will exit in this case.</em>

SplitPath, SourceFile,, SourceFilePath,, SourceFileNoExt
DestFile := SourceFilePath "\" SourceFileNoExt " Extracted Links.txt"

if FileExist(DestFile)
{
    MsgBox, 4,, Overwrite the existing links file? Press No to append to it.`n`nFILE: %DestFile%
    IfMsgBox, Yes
        FileDelete, %DestFile%
}

LinkCount := 0
Loop, read, %SourceFile%, %DestFile%
{
    URLSearchString := A_LoopReadLine
    Gosub, URLSearch
}
MsgBox %LinkCount% links were found and written to &quot;%DestFile%&quot;.
return


URLSearch:
<em>; It's done this particular way because some URLs have other URLs embedded inside them:</em>
URLStart1 := InStr(URLSearchString, "https://")
URLStart2 := InStr(URLSearchString, "http://")
URLStart3 := InStr(URLSearchString, "ftp://")
URLStart4 := InStr(URLSearchString, "www.")

<em>; Find the left-most starting position:</em>
URLStart := URLStart1  <em>; Set starting default.</em>
Loop
{
    <em>; It helps performance (at least in a script with many variables) to resolve</em>
    <em>; &quot;URLStart%A_Index%&quot; only once:</em>
    ArrayElement := URLStart%A_Index%
    if (ArrayElement = "")  <em>; End of the <a href="../misc/Arrays.htm#pseudo">pseudo-array</a> has been reached.</em>
        break
    if (ArrayElement = 0)  <em>; This element is disqualified.</em>
        continue
    if (URLStart = 0)
        URLStart := ArrayElement
    else <em>; URLStart has a valid position in it, so compare it with ArrayElement.</em>
    {
        if (ArrayElement != 0)
            if (ArrayElement &lt; URLStart)
                URLStart := ArrayElement
    }
}

if (URLStart = 0)  <em>; No URLs exist in URLSearchString.</em>
    return

<em>; Otherwise, extract this URL:</em>
URL := SubStr(URLSearchString, URLStart)  <em>; Omit the beginning/irrelevant part.</em>
Loop, parse, URL, %A_Tab%%A_Space%&lt;&gt;  <em>; Find the first space, tab, or angle (if any).</em>
{
    URL := A_LoopField
    break  <em>; i.e. perform only one loop iteration to fetch the first &quot;field&quot;.</em>
}
<em>; If the above loop had zero iterations because there were no ending characters found,
; leave the contents of the URL var untouched.</em>

<em>; If the URL ends in a double quote, remove it.  For now, StringReplace is used, but
; note that it seems that double quotes can legitimately exist inside URLs, so this
; might damage them:</em>
StringReplace, URLCleansed, URL, &quot;,, All
FileAppend, %URLCleansed%`n
LinkCount += 1

<em>; See if there are any other URLs in this line:</em>
CharactersToOmit := StrLen(URL)
CharactersToOmit += URLStart
URLSearchString := SubStr(URLSearchString, CharactersToOmit)
Gosub, URLSearch  <em>; Recursive call to self.</em>
return</pre>
</div>

</body>
</html>
